0
1
00:00:00,870 --> 00:00:07,050
All right so now it's time to visualize our mean squared error cost function.
1

2
00:00:07,170 --> 00:00:13,830
Now I don't know about you but I can't look at these equations and picture what they actually look like
2

3
00:00:13,950 --> 00:00:14,760
in my head.
3

4
00:00:14,770 --> 00:00:19,890
I'm the kind of person who really needs a graph or a chart or something visual to really understand
4

5
00:00:19,890 --> 00:00:21,340
what's going on.
5

6
00:00:21,350 --> 00:00:30,240
So let me insert a subheading here with Markdown, two pound symbols and I'll just write "3D plot for the
6

7
00:00:30,300 --> 00:00:40,860
MSE cost function" and let's have a subheading here that reads "Make data for thetas".
7

8
00:00:42,030 --> 00:00:49,110
The first step in creating our plot is to create a whole range of theta values that we can use to calculate
8

9
00:00:49,200 --> 00:00:50,860
the mean squared error for.
9

10
00:00:51,150 --> 00:00:58,020
So remember I said that the cost function depends on the parameter values and not the data itself,
10

11
00:00:58,050 --> 00:01:03,060
not the x_5 or the y_5 arrays but it depends on the theta.
11

12
00:01:03,270 --> 00:01:06,600
That's what the cost function is trying to map.
12

13
00:01:06,600 --> 00:01:12,090
The first thing that I am going to do is I'm going to set the number of data points for our chart.
13

14
00:01:12,090 --> 00:01:15,010
I'm going to call this nr_thetas.
14

15
00:01:15,060 --> 00:01:16,200
It's gonna be a variable.
15

16
00:01:16,470 --> 00:01:19,690
And to start off with I'm going to set it equal to 5.
16

17
00:01:20,130 --> 00:01:23,300
And then I'm going to create our data points.
17

18
00:01:23,340 --> 00:01:27,390
So I'll create a variable called th_0,
18

19
00:01:27,390 --> 00:01:32,170
I'm going to set that equal to the return value from numpy's linspace function.
19

20
00:01:32,160 --> 00:01:37,200
That's gonna be "np.linspace()".
20

21
00:01:37,530 --> 00:01:40,810
And then we're gonna supply three inputs - 
21

22
00:01:40,830 --> 00:01:41,760
start value,
22

23
00:01:41,760 --> 00:01:51,480
we're gonna say -1; stop value we're going to say is equal to 3, and a number of intervals, so the number
23

24
00:01:51,480 --> 00:01:57,220
of points that we're gonna create, I'm going gonna set that equal to "nr_thetas".
24

25
00:01:57,510 --> 00:02:06,780
So that way when we look at th_0, we see that it has 5 values it's an array of 1, 2, 3, 4, 5
25

26
00:02:06,990 --> 00:02:08,250
items.
26

27
00:02:08,790 --> 00:02:16,530
Then I'm going to copy this line of code here, paste it in and have the same thing for theta_1, theta_1 is also
27

28
00:02:16,530 --> 00:02:22,260
going to go from -1 to 3 and it's going to have 5 values.
28

29
00:02:22,260 --> 00:02:28,460
So what we've done here is we've created a one dimensional array, but we're gonna have a 3D plot,
29

30
00:02:28,490 --> 00:02:31,540
so we're going to need a two dimensional array.
30

31
00:02:31,560 --> 00:02:37,950
We're not plotting a line, we're plotting a surface and for these we need an array of two dimensions.
31

32
00:02:38,640 --> 00:02:45,560
The way we're gonna create a two dimensional array is by using numpy's mesh grid function.
32

33
00:02:45,560 --> 00:02:47,200
So we've done this before.
33

34
00:02:47,200 --> 00:02:53,430
And just to differentiate between the one dimensional and two dimensional variables I'll create another
34

35
00:02:53,430 --> 00:02:54,260
set.
35

36
00:02:54,300 --> 00:03:07,080
So I'm going to say "plot_t0, plot_t1 = np.meshgrid()", so meshgrid is the
36

37
00:03:07,080 --> 00:03:14,250
function that will give us a two dimensional array and we're are using this comma notation "plot_t0,
37

38
00:03:14,250 --> 00:03:21,400
plot_t1" as a way of unpacking a sequence because meshgrid will return to us a tuple. Meshgrid in
38

39
00:03:21,400 --> 00:03:28,950
turn needs two inputs, so it's gonna be theta 0 and theta 1. From these inputs it's going to create
39

40
00:03:29,250 --> 00:03:31,050
our 2D arrays.
40

41
00:03:31,380 --> 00:03:39,810
So if we look at "th_0.shape" we'll see it's a flat array, one dimensional with 5
41

42
00:03:39,840 --> 00:03:47,880
elements and if we compare that to "plot_t0.shape" then we see that it is a 5 by
42

43
00:03:47,880 --> 00:03:55,580
5 array. It's two dimensional It has 25 elements total so if I delete the ".shape" and
43

44
00:03:55,570 --> 00:04:02,410
I press Shift+Enter I can see it here it looks like this - 5 by 5, 25 elements total.
44

45
00:04:02,610 --> 00:04:10,470
Now it's time to calculate the mean squared error for all the theta 0 and all the theta 1 values
45

46
00:04:10,920 --> 00:04:13,050
in our range.
46

47
00:04:13,140 --> 00:04:21,570
So let me ask you this - do you think that the cost that we calculate will have one dimension or will
47

48
00:04:21,570 --> 00:04:30,720
it have two dimensions? And the answer is it's also gonna be two dimensional - the surface plot needs to
48

49
00:04:30,720 --> 00:04:37,140
know the mean squared error value for all the combinations of theta zeros and theta ones - we're gonna
49

50
00:04:37,140 --> 00:04:41,460
be plotting a surface not a line after all.
50

51
00:04:41,460 --> 00:04:48,390
So here's what we're gonna do - we're gonna start out with a two dimensional array of just zeros and then
51

52
00:04:48,390 --> 00:04:54,730
we're gonna calculate the mean squared error for each value in our array separately.
52

53
00:04:55,050 --> 00:05:01,110
This will give us a chance to learn about another Python programming technique, which is very, very common
53

54
00:05:01,680 --> 00:05:05,190
and that's using nested loops.
54

55
00:05:05,190 --> 00:05:12,510
Let's add this as a subheading actually, so I am going to change this to Markdown, three pound signs and then I'm going to say
55

56
00:05:14,160 --> 00:05:23,400
"Calc MSE using nested for loops". Going to add a few more cells down here.
56

57
00:05:23,400 --> 00:05:25,350
Keep working in the middle of the screen.
57

58
00:05:26,040 --> 00:05:33,780
And the first thing I'm going to do now is I'm going to create a two dimensional array just of zeroes, so
58

59
00:05:33,780 --> 00:05:38,910
numpy actually has a function called zeros which is perfect for this.
59

60
00:05:38,910 --> 00:05:44,070
All we need to do is supply the dimensions of the array that we want as an output.
60

61
00:05:44,070 --> 00:05:49,770
So the variable that's going to hold on to all our mean squared error calculations is going gonna be
61

62
00:05:49,770 --> 00:05:52,470
called "plot_cost"
62

63
00:05:52,680 --> 00:05:57,340
and that's gonna be equal to the return value from this zeros
63

64
00:05:57,390 --> 00:05:58,610
function that I mentioned.
64

65
00:05:58,860 --> 00:06:03,270
So "np.zeros()"
65

66
00:06:03,600 --> 00:06:07,350
and then inside the parentheses we supply the dimensions.
66

67
00:06:07,350 --> 00:06:10,620
So if I supply 2 by 3,
67

68
00:06:10,620 --> 00:06:16,590
So "2,3" and then say "plot_cost",
68

69
00:06:17,290 --> 00:06:21,600
I can see what a 2 by 3 array of zeros will look like.
69

70
00:06:21,610 --> 00:06:26,620
There'll be 3 columns and 2 rows, 2 rows 3 columns.
70

71
00:06:26,620 --> 00:06:28,660
If it's 5 by 5,
71

72
00:06:28,720 --> 00:06:33,670
on the other hand it'll be 5 rows and 5 columns.
72

73
00:06:33,670 --> 00:06:37,320
Now I'm not going to have a hardcoded 5 in here.
73

74
00:06:37,320 --> 00:06:46,600
Instead I'm going to use the "nr_thetas" variable and and feed it as an argument to
74

75
00:06:46,690 --> 00:06:48,530
our zeros function.
75

76
00:06:48,550 --> 00:06:54,130
So what I'm going to do is I'm going to supply a tuple, which you can see by the two parentheses and it's
76

77
00:06:54,130 --> 00:06:58,330
gonna be square, it's gonna be symmetrical, so it's going to have the same number of rows and the same
77

78
00:06:58,330 --> 00:07:00,100
number of columns.
78

79
00:07:00,220 --> 00:07:06,310
So it'll be "nr_thetas, nr_thetas".
79

80
00:07:06,430 --> 00:07:10,150
This is gonna be the input to our zeros function,
80

81
00:07:10,210 --> 00:07:17,080
so if I ever have to change my variable up here and update this cell then my plot_cost
81

82
00:07:17,080 --> 00:07:19,790
will update as well.
82

83
00:07:19,810 --> 00:07:23,470
Now it's time to talk about nested loops.
83

84
00:07:23,560 --> 00:07:31,010
Let me add that as a comment here, say "Nested loop practice".
84

85
00:07:31,030 --> 00:07:32,550
Let me show you what I mean.
85

86
00:07:32,560 --> 00:07:38,110
So to create a nested loop, we're going to use two for loops.
86

87
00:07:38,110 --> 00:07:45,550
So the first for loop it's gonna look like this, is gonna read "for i in range()" and then say the number
87

88
00:07:45,550 --> 00:07:52,330
3 between the parentheses, then colon, and then inside this for loop there'll be another for loop.
88

89
00:07:52,390 --> 00:08:01,700
So I'm going to write "for j in range(3):" and inside the second for loop,
89

90
00:08:01,870 --> 00:08:03,710
I'm going to put a print statement.
90

91
00:08:03,970 --> 00:08:14,470
So, let me print the string "Hello" and hit Shift+Enter and what we see is that hello is printed a total
91

92
00:08:14,560 --> 00:08:22,480
of 9 times so, three, three and three; 3 times 3 is 9.
92

93
00:08:22,480 --> 00:08:24,450
So this is how many times we print "Hello".
93

94
00:08:25,420 --> 00:08:29,440
Let's go a step further than just printing "Hello" nine times.
94

95
00:08:29,530 --> 00:08:35,020
Let me show you another way of doing the string interpolation with Python.
95

96
00:08:35,110 --> 00:08:39,760
This is a different way that we can work with the strings from what we've seen before.
96

97
00:08:39,850 --> 00:08:43,550
This particular method is called an "fstring".
97

98
00:08:43,600 --> 00:08:47,300
It's an fstring because there's an "f" right in front of the string.
98

99
00:08:47,500 --> 00:08:54,580
So it's gonna be "f" and then you have the single or double quotes and then within the string itself I'm
99

100
00:08:54,580 --> 00:09:05,290
going to say "value of i is" and then I'm going to use a set of curly braces and inside these curly
100

101
00:09:05,290 --> 00:09:09,720
braces, I can access a variable in my Python code.
101

102
00:09:09,760 --> 00:09:13,230
So for example I can access this variable
102

103
00:09:13,240 --> 00:09:16,990
i here, the iterator in my outer loop. So I'm going to
103

104
00:09:17,020 --> 00:09:18,140
say "i"
104

105
00:09:18,340 --> 00:09:25,510
in between the curly braces, and then I'm going to continue "and j is",
105

106
00:09:25,510 --> 00:09:28,640
and then another set of curly braces,
106

107
00:09:28,920 --> 00:09:33,740
and then inside these curly braces I'm going to actually put the value "j".
107

108
00:09:33,850 --> 00:09:41,860
So I'm accessing this variable, the second iterator the one for the inner for loop. And
108

109
00:09:41,880 --> 00:09:45,470
now I'm going to hit Shift+Enter', see what we get.
109

110
00:09:45,480 --> 00:09:53,250
So what we see here is that the values that are printed out from inside these curly braces change every
110

111
00:09:53,250 --> 00:10:00,640
time the loop is executed by having this special notation, the f in front and then the curly braces were
111

112
00:10:00,660 --> 00:10:07,180
able to tell Python that something inside this string should not be considered a string.
112

113
00:10:07,210 --> 00:10:12,630
Instead we're able to reference values that are stored in variables elsewhere.
113

114
00:10:12,630 --> 00:10:18,990
Now the other thing that's really, really cool about this particular pattern is that we can see what happened
114

115
00:10:19,230 --> 00:10:23,560
exactly when our loop executed 9 times.
115

116
00:10:23,610 --> 00:10:26,220
So before we had "Hello" printed 9 times.
116

117
00:10:26,250 --> 00:10:32,760
But this time we can see what's actually going on and how these i and j values are changing. When the loop
117

118
00:10:32,760 --> 00:10:34,050
first starts out,
118

119
00:10:34,390 --> 00:10:35,970
i is equal to 0,
119

120
00:10:36,090 --> 00:10:38,730
and j is equal to 0.
120

121
00:10:38,730 --> 00:10:47,370
And then what happens is that the inner loop executes three times, j becomes equal to 1 and then to 2.
121

122
00:10:47,400 --> 00:10:50,700
And after that it's done executing.
122

123
00:10:50,700 --> 00:10:54,000
And then the outer loop increments by 1.
123

124
00:10:54,030 --> 00:11:02,400
So i goes from 0 to 1, and then it's j's turn again; j goes from 0 to 2, executes 3 times
124

125
00:11:02,910 --> 00:11:05,370
and the whole thing repeats one final time.
125

126
00:11:06,180 --> 00:11:13,230
So one of the things you can probably already tell is how this might be applied to many, many different
126

127
00:11:13,230 --> 00:11:15,110
kinds of problems.
127

128
00:11:15,210 --> 00:11:24,750
In particular it goes very, very well with iterating through a 2D array or a 2D matrix. If you want to
128

129
00:11:24,750 --> 00:11:31,080
hit up every single value then you can go row by row and column by column.
129

130
00:11:31,320 --> 00:11:34,900
And this is exactly what we're going to do.
130

131
00:11:34,920 --> 00:11:40,620
The important thing with this sort of stuff as with all Python code is to make sure the indentation
131

132
00:11:40,950 --> 00:11:48,150
is correct and that way Python knows that this loop is indeed nested inside this first one.
